﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using IntillisenseLib;
using Khendys.Controls;

namespace LittleSolution
{
    public partial class ucDefineLittle : UserControl
    {
        private MessageTemplate currentMessage=null;
        private ObjectTemplete findObjectResult = null;
        private ObjectTemplete selectedObj = null;

        private string typed = "";
        private bool wordMatched = false;

        private Bitmap contactImage;

        public ucDefineLittle()
        {
            InitializeComponent();
            contactImage = new Bitmap(imageList1.Images[1]);
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            frmDefineTeamplate defineTemplate = new frmDefineTeamplate();
            if (defineTemplate.ShowDialog()==DialogResult.OK)
            {
                MessageTemplate msg = new MessageTemplate(defineTemplate.MessageName);
                AppDoc.GetInstance().AddMessage(msg);
                currentMessage = msg;

                lbMessageTemplate.Items.Add(msg.MessageName);
                rtbxMessage.Text = "";
                rtbxMessage.ReadOnly = false;
                rtbxMessage.Focus();
            }
        }

        private void rtbxMessage_KeyDown(object sender, KeyEventArgs e)
        {
            // Keep track of the current character, used
            // for tracking whether to hide the list of members,
            // when the delete button is pressed
            int i = this.rtbxMessage.SelectionStart;
            string currentChar = "";

            if (i > 0)
            {
                currentChar = this.rtbxMessage.Text.Substring(i - 1, 1);
            }

            if ((e.Shift && e.KeyCode==Keys.D2) ||(e.KeyCode==Keys.OemPeriod))
            {
                // The amazing dot key

                if (!this.gListBox1.Visible)
                {
                    // Display the member listview if there are
                    // items in it
                    if (populateListBox())
                    {
                        //this.gListBox1.SelectedIndex = 0;

                        // Find the position of the caret
                        Point point = this.rtbxMessage.GetPositionFromCharIndex(rtbxMessage.SelectionStart);
                        point.Y += (int)Math.Ceiling(this.rtbxMessage.Font.GetHeight()) + 2;
                        point.X += 2; // for Courier, may need a better method
                        
                        this.gListBox1.Location = point;
                        this.gListBox1.BringToFront();
                        this.gListBox1.Show();
                    }
                }
                else
                {
                    this.gListBox1.Hide();
                    typed = "";
                }

            }
            else if (e.KeyCode == Keys.Back)
            {
                // Delete key - hides the member list if the character
                // being deleted is a dot

                if (typed.Length > 0)
                {
                    typed = typed.Substring(0, typed.Length - 1);
                }
                if (currentChar == "@")
                {
                    this.gListBox1.Hide();
                }

            }
            else if (e.KeyCode == Keys.Up)
            {
                // The up key moves up our member list, if
                // the list is visible                

                if (this.gListBox1.Visible)
                {
                    this.wordMatched = true;
                    if (this.gListBox1.SelectedIndex > 0)
                        this.gListBox1.SelectedIndex--;

                    e.Handled = true;
                }
            }
            else if (e.KeyCode == Keys.Down)
            {
                // The up key moves down our member list, if
                // the list is visible                

                if (this.gListBox1.Visible)
                {
                    this.wordMatched = true;
                    if (this.gListBox1.SelectedIndex < this.gListBox1.Items.Count - 1)
                        this.gListBox1.SelectedIndex++;

                    e.Handled = true;
                }
            }                       
            else if (e.KeyValue < 48 || (e.KeyValue >= 58 && e.KeyValue <= 64) || (e.KeyValue >= 91 && e.KeyValue <= 96) || e.KeyValue > 122)
            {
                // Check for any non alphanumerical key, hiding
                // member list box if it's visible.

                if (this.gListBox1.Visible)
                {
                    // Check for keys for autofilling (return,tab,space)
                    // and autocomplete the richtextbox when they're pressed.
                    if (e.KeyCode == Keys.Return || e.KeyCode == Keys.Tab || e.KeyCode == Keys.Space)
                    {                        

                        // Autocomplete
                        this.selectItem();

                        this.typed = "";
                        this.wordMatched = false;
                        e.Handled = true;
                    }

                    // Hide the member list view
                    this.gListBox1.Hide();
                }
            }
            else
            {
                // Letter or number typed, search for it in the listview
                if (this.gListBox1.Visible)
                {
                    char val = (char)e.KeyValue;
                    this.typed += val;

                    this.wordMatched = false;

                    // Loop through all the items in the listview, looking
                    // for one that starts with the letters typed
                    for (i = 0; i < this.gListBox1.Items.Count; i++)
                    {
                        if (this.gListBox1.Items[i].ToString().ToLower().StartsWith(this.typed.ToLower()))
                        {
                            this.wordMatched = true;
                            this.gListBox1.SelectedIndex = i;
                            break;
                        }
                    }
                }
                else
                {
                    this.typed = "";
                }
            }
        }

        private void selectItem()
        {
            if (this.wordMatched)
            {
                int selstart = this.rtbxMessage.SelectionStart;
                int prefixend = this.rtbxMessage.SelectionStart - typed.Length;
                int suffixstart = this.rtbxMessage.SelectionStart + typed.Length;

                if (suffixstart >= this.rtbxMessage.Text.Length)
                {
                    suffixstart = this.rtbxMessage.Text.Length;
                }

                string prefix = this.rtbxMessage.Text.Substring(0, prefixend);
                string suffix = this.rtbxMessage.Text.Substring(suffixstart, this.rtbxMessage.Text.Length - suffixstart);

                selectedObj = ((GListBoxItem)this.gListBox1.SelectedItem).MyObject as ObjectTemplete;

                string fill = "";
                switch (selectedObj.ObjType)
                {
                    case eObjectType.TEXT:
                        fill = selectedObj.GetParameterValue();
                        rtbxMessage.AppendTextAsRtf(fill);
                        //this.rtbxMessage.Text = prefix + fill + suffix;
                        this.rtbxMessage.SelectionStart = prefix.Length + fill.Length;
                        break;
                    case eObjectType.CONTACT:
                        fill = selectedObj.GetParameterDisplayName();
                        //                         rtbxMessage.Text = rtbxMessage.Text.Substring(0, rtbxMessage.Text.Length - 1);
                        //                         rtbxMessage.SelectionStart = rtbxMessage.Text.Length;
                        rtbxMessage.SelectionStart = rtbxMessage.SelectionStart - 1;
                        rtbxMessage.InsertImage(contactImage);
                        rtbxMessage.Text.Remove(rtbxMessage.Text.Length - 1);
                        Font oldFont = rtbxMessage.Font;
                        Font font = new Font(FontFamily.GenericSansSerif, 9, FontStyle.Underline);
                        rtbxMessage.AppendTextAsRtf(fill, font, RtfColor.Blue);
                        this.rtbxMessage.SelectionStart = rtbxMessage.Text.Length;
                        rtbxMessage.Select(rtbxMessage.SelectionStart, 0);
                        rtbxMessage.SelectionFont = oldFont;
                        rtbxMessage.SelectionColor = Color.Black;
                        break;
                    case eObjectType.PLACEHOLDER:
                        fill = selectedObj.GetParameterDisplayName();
                        oldFont = rtbxMessage.Font;
                        font = new Font(FontFamily.GenericSansSerif, 9, FontStyle.Underline);
                        rtbxMessage.AppendTextAsRtf(fill, font, RtfColor.Blue);
                        rtbxMessage.SelectionFont = oldFont;
                        rtbxMessage.SelectionColor = Color.Black;

                        break;
                }


            }
        }
        /// <summary>
        /// Searches backwards from the current caret position, until
        /// a space or newline is found.
        /// </summary>
        /// <returns>The previous word from the carret position</returns>
        private string getLastWord()
        {
            string word = "";

            int pos = this.rtbxMessage.SelectionStart;
            if (pos > 1)
            {

                string tmp = "";
                char f = new char();
                while (f != ' ' && f != 10 && pos > 0)
                {
                    pos--;
                    tmp = this.rtbxMessage.Text.Substring(pos, 1);
                    f = (char)tmp[0];
                    word += f;
                }

                char[] ca = word.ToCharArray();
                Array.Reverse(ca);
                word = new String(ca);

            }
            return word.Trim();

        }
        private bool populateListBox()
        {
            bool result = false;
            string word = this.getLastWord();

            //System.Diagnostics.Debug.WriteLine(" - Path: " +word);

            findObjectResult = null;
            if (word == "")
            {
                FindObject(word, AppDoc.GetInstance().ObjRoot);
            }
            else
            {
                word = word.Substring(1, word.Length - 1);
                FindObject(word, AppDoc.GetInstance().ObjRoot);
            }


            if (this.findObjectResult != null)
            {
                this.gListBox1.Items.Clear();

                if (this.findObjectResult != null && findObjectResult.GetAllChilds().Count > 0)
                {
                    result = true;

                    // Sort alphabetically (this could be replaced with
                    // a sortable treeview)
                    MemberItem[] items = new MemberItem[this.findObjectResult.GetAllChilds().Count];
                    for (int n = 0; n < this.findObjectResult.GetAllChilds().Count; n++)
                    {
                        MemberItem memberItem = new MemberItem();
                        memberItem.Obj = this.findObjectResult.GetAllChilds()[n];
                        memberItem.DisplayText = this.findObjectResult.GetAllChilds()[n].GetParameterDisplayName();
                        memberItem.Tag = this.findObjectResult.GetAllChilds()[n].ObjType;

                        items[n] = memberItem;
                    }
                    Array.Sort(items);

                    for (int n = 0; n < items.Length; n++)
                    {
                        int imageindex = 0;

                        if (items[n].Tag != null)
                        {
                            // Default to method (contains text for parameters)
                            imageindex = 2;
                            if (items[n].Tag is eObjectType)
                            {
                                eObjectType memberType = (eObjectType)items[n].Tag;

                                switch (memberType)
                                {
                                    case eObjectType.TEXT:
                                        imageindex = 0;
                                        break;
                                    case eObjectType.CONTACT:
                                        imageindex = 1;
                                        break;
                                    case eObjectType.PLACEHOLDER:
                                        imageindex = 2;
                                        break;
                                }
                            }
                        }
                        this.gListBox1.Items.Add(new GListBoxItem(items[n].Obj, imageindex));
                    }
                }
            }

            return result;
        }

        private void FindObject(string path, ObjectTemplete list)
        {
            if (list.GetFullPath() == path)
            {
                this.findObjectResult = list;
                return;
            }
            if (list.GetAllChilds() != null)
            {
                for (int i = 0; i < list.GetAllChilds().Count; i++)
                {
                    FindObject(path, list.GetAllChilds()[i]);
                }
            }            
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            rtbxMessage.SaveFile("D:\\test.rtf", RichTextBoxStreamType.RichText);
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            rtbxMessage.LoadFile("D:\\test.rtf");
        }

        private void gListBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Make sure when an item is selected, control is returned back to the richtext
            this.rtbxMessage.Focus();
        }

        private void gListBox1_DoubleClick(object sender, EventArgs e)
        {
            // Item double clicked, select it
            if (this.gListBox1.SelectedItems.Count == 1)
            {
                this.wordMatched = true;
                this.selectItem();
                this.gListBox1.Hide();
                this.rtbxMessage.Focus();
                this.wordMatched = false;
            }
        }       
    }
    #region MemberItem class
    /// <summary>
    /// Used for storing member items which are then
    /// alphabetically sorted.
    /// </summary>
    public class MemberItem : IComparable
    {
        public string DisplayText;
        public object Tag;
        public ObjectTemplete Obj;

        public int CompareTo(object obj)
        {
            int result = 1;
            if (obj != null)
            {
                if (obj is MemberItem)
                {
                    MemberItem memberItem = (MemberItem)obj;
                    return (this.DisplayText.CompareTo(memberItem.DisplayText));
                }
                else
                {
                    throw new ArgumentException();
                }
            }


            return result;
        }
    }
    #endregion
}
